home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Windows Game Programming for Dummies (2nd Edition)
/
WinGamProgFD.iso
/
mac
/
DirectX SDK
/
DXSDK
/
samples
/
Multimedia
/
DirectPlay
/
LobbyClient
/
LobbyClient.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2001-10-31
|
43KB
|
1,082 lines
//----------------------------------------------------------------------------
// File: LobbyClient.cpp
//
// Desc: LobbyClient is a simple lobby client. It displays all registered DirectPlay
// applications on the local system. It allows the
// user to launch one or more of these applications using a chosen
// service provider. A launched lobbied application may be told to either
// join or host a game.
//
// Copyright (c) 1999-2001 Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include <winsock.h>
#include <windows.h>
#include <basetsd.h>
#include <dplay8.h>
#include <dplobby8.h>
#include <dpaddr.h>
#include <dxerr8.h>
#include <cguid.h>
#include <tchar.h>
#include "DXUtil.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// Defines, and constants
//-----------------------------------------------------------------------------
#define DPLAY_SAMPLE_KEY TEXT("Software\\Microsoft\\DirectX DirectPlay Samples")
#define WM_APP_APPDISCONNECTED (WM_APP + 1)
#define WM_APP_SETSTATUS (WM_APP + 2)
//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
IDirectPlay8Peer* g_pDP = NULL; // DirectPlay peer object
IDirectPlay8LobbyClient* g_pLobbyClient = NULL; // DirectPlay lobby client
HINSTANCE g_hInst = NULL; // HINST of app
HWND g_hDlg = NULL; // HWND of main dialog
TCHAR g_strAppName[256] = TEXT("LobbyClient");
GUID* g_pCurSPGuid = NULL; // Currently selected guid
TCHAR g_strPlayerName[MAX_PATH]; // Local player name
TCHAR g_strSessionName[MAX_PATH]; // Session name
TCHAR g_strPreferredProvider[MAX_PATH]; // Provider string
TCHAR g_strLocalIP[MAX_PATH]; // Provider string
//-----------------------------------------------------------------------------
// Function-prototypes
//-----------------------------------------------------------------------------
HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext, DWORD dwMessageId, PVOID pMsgBuffer );
INT_PTR CALLBACK LobbyClientDlgProc( HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam );
HRESULT InitDirectPlay();
HRESULT OnInitDialog( HWND hDlg );
VOID SetupAddressFields( HWND hDlg );
HRESULT AllocAndInitConnectSettings( HWND hDlg, GUID* pAppGuid, DPL_CONNECTION_SETTINGS** ppdplConnectSettings );
VOID FreeConnectSettings( DPL_CONNECTION_SETTINGS* pSettings );
HRESULT LaunchApp( HWND hDlg );
HRESULT EnumRegisteredApplications( HWND hDlg );
HRESULT EnumServiceProviders( HWND hDlg );
HRESULT EnumAdapters( HWND hDlg, GUID* pSPGuid );
HRESULT SendMsgToApp( HWND hDlg );
HRESULT DisconnectFromApp( HWND hDlg );
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: Entry point for the application. Since we use a simple dialog for
// user interaction we don't need to pump messages.
//-----------------------------------------------------------------------------
INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst,
LPSTR pCmdLine, INT nCmdShow )
{
HRESULT hr;
HKEY hDPlaySampleRegKey;
g_hInst = hInst;
// Read persistent state information from registry
RegCreateKeyEx( HKEY_CURRENT_USER, DPLAY_SAMPLE_KEY, 0, NULL,
REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL,
&hDPlaySampleRegKey, NULL );
DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"),
g_strPlayerName, MAX_PATH, TEXT("TestPlayer") );
DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"),
g_strSessionName, MAX_PATH, TEXT("TestGame") );
DXUtil_ReadStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"),
g_strPreferredProvider, MAX_PATH,
TEXT("DirectPlay8 TCP/IP Service Provider") );
// Init COM so we can use CoCreateInstance
CoInitializeEx( NULL, COINIT_MULTITHREADED );
if( FAILED( hr = InitDirectPlay() ) )
{
DXTRACE_ERR( TEXT("InitDirectPlay"), hr );
MessageBox( NULL, TEXT("Failed initializing IDirectPlay8Peer. ")
TEXT("The sample will now quit."),
g_strAppName, MB_OK | MB_ICONERROR );
return FALSE;
}
DialogBox( hInst, MAKEINTRESOURCE(IDD_LOBBY_CLIENT), NULL,
(DLGPROC) LobbyClientDlgProc );
if( g_pLobbyClient )
{
g_pLobbyClient->Close( 0 );
SAFE_RELEASE( g_pLobbyClient );
}
if( g_pDP )
{
g_pDP->Close(0);
SAFE_RELEASE( g_pDP );
}
CoUninitialize();
// Write information to the registry
DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Player Name"), g_strPlayerName );
DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Session Name"), g_strSessionName );
DXUtil_WriteStringRegKey( hDPlaySampleRegKey, TEXT("Preferred Provider"), g_strPreferredProvider );
RegCloseKey( hDPlaySampleRegKey );
return TRUE;
}
//-----------------------------------------------------------------------------
// Name: InitDirectPlay()
// Desc:
//-----------------------------------------------------------------------------
HRESULT InitDirectPlay()
{
HRESULT hr;
// Create and init IDirectPlay8Peer
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Peer, NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Peer,
(LPVOID*) &g_pDP ) ) )
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
if( FAILED( hr = g_pDP->Initialize( NULL, DirectPlayMessageHandler, 0 ) ) )
return DXTRACE_ERR( TEXT("Initialize"), hr );
// Create and init IDirectPlay8LobbyClient
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8LobbyClient, NULL,
CLSCTX_INPROC_SERVER,
IID_IDirectPlay8LobbyClient,
(LPVOID*) &g_pLobbyClient ) ) )
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
if( FAILED( hr = g_pLobbyClient->Initialize( NULL, DirectPlayLobbyMessageHandler, 0 ) ) )
return DXTRACE_ERR( TEXT("Initialize"), hr );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: LobbyClientDlgProc()
// Desc: Handles dialog messages
//-----------------------------------------------------------------------------
INT_PTR CALLBACK LobbyClientDlgProc( HWND hDlg, UINT msg,
WPARAM wParam, LPARAM lParam )
{
HRESULT hr;
switch( msg )
{
case WM_INITDIALOG:
{
g_hDlg = hDlg;
if( FAILED( hr = OnInitDialog( hDlg ) ) )
{
DXTRACE_ERR( TEXT("OnInitDialog"), hr );
MessageBox( NULL, TEXT("Failed initializing dialog box. ")
TEXT("The sample will now quit."),
g_strAppName, MB_OK | MB_ICONERROR );
EndDialog( hDlg, 0 );
}
break;
}
case WM_APP_APPDISCONNECTED:
{
// This is an app defined msg that keeps the
// lobby message handler from blocking on the dialog thread.
DPNHANDLE hDisconnectId = (DPNHANDLE) lParam;
HRESULT hrReason = (HRESULT) wParam;
// Remove this connection from the list
TCHAR strBuffer[200];
wsprintf( strBuffer, TEXT("0x%x"), hDisconnectId );
int nIndex = (int) SendDlgItemMessage( g_hDlg, IDC_ACTIVE_CONNECTIONS,
LB_FINDSTRINGEXACT, -1, (LPARAM) strBuffer );
SendDlgItemMessage( g_hDlg, IDC_ACTIVE_CONNECTIONS, LB_DELETESTRING, nIndex, 0 );
// Tell the user
wsprintf( strBuffer, TEXT("0x%x was disconnected. Reason: 0x%0.8x"),
hDisconnectId, hrReason );
MessageBox( g_hDlg, strBuffer, g_strAppName, MB_OK );
break;
}
case WM_APP_SETSTATUS:
{
// This is an app defined msg that keeps the
// lobby message handler from blocking on the dialog thread.
TCHAR* strBuffer = (TCHAR*) lParam;
if( strBuffer )
{
SetDlgItemText( g_hDlg, IDC_STATUS, strBuffer );
SAFE_DELETE_ARRAY( strBuffer );
}
break;
}
case WM_COMMAND:
{
switch( LOWORD(wParam) )
{
case IDC_HOST_SESSION:
SetupAddressFields( hDlg );
break;
case IDC_SP_COMBO:
{
// If the pSPGuid changed then re-enum the adapters, and
// update the address fields.
int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
if( pSPGuid != NULL && g_pCurSPGuid != pSPGuid )
{
g_pCurSPGuid = pSPGuid;
SetupAddressFields( hDlg );
EnumAdapters( hDlg, pSPGuid );
}
break;
}
case IDC_LAUNCH:
if( FAILED( hr = LaunchApp( hDlg ) ) )
{
DXTRACE_ERR( TEXT("LaunchApp"), hr );
MessageBox( NULL, TEXT("Failure trying to launch app. ")
TEXT("The sample will now quit."),
g_strAppName, MB_OK | MB_ICONERROR );
EndDialog( hDlg, 0 );
}
break;
case IDC_SEND_MSG:
// Send a dummy message to a connected app for demo purposes
SendMsgToApp( hDlg );
break;
case IDC_DISCONNECT:
// Disconnect from an app
DisconnectFromApp( hDlg );
break;
case IDCANCEL:
EndDialog( hDlg, 0 );
return TRUE;
}
break;
}
case WM_DESTROY:
{
GetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strPlayerName, MAX_PATH );
GetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName, MAX_PATH );
int nIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETLBTEXT, nIndex, (LPARAM) g_strPreferredProvider );
GUID* pGuid;
int nCount,i;
nCount = (int)SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_GETCOUNT, 0, 0 );
for( i=0; i<nCount; i++ )
{
pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_GETITEMDATA, i, 0 );
SAFE_DELETE( pGuid );
}
nCount = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCOUNT, 0, 0 );
for( i=0; i<nCount; i++ )
{
pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, i, 0 );
SAFE_DELETE( pGuid );
}
nCount = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCOUNT, 0, 0 );
for( i=0; i<nCount; i++ )
{
pGuid = (LPGUID) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETITEMDATA, i, 0 );
SAFE_DELETE( pGuid );
}
break;
}
}
return FALSE; // Didn't handle message
}
//-----------------------------------------------------------------------------
// Name: OnInitDialog
// Desc:
//-----------------------------------------------------------------------------
HRESULT OnInitDialog( HWND hDlg )
{
HRESULT hr;
// Load and set the icon
HICON hIcon = LoadIcon( g_hInst, MAKEINTRESOURCE( IDI_MAIN ) );
SendMessage( hDlg, WM_SETICON, ICON_BIG, (LPARAM) hIcon ); // Set big icon
SendMessage( hDlg, WM_SETICON, ICON_SMALL, (LPARAM) hIcon ); // Set small icon
CheckDlgButton( hDlg, IDC_HOST_SESSION, BST_CHECKED );
CheckRadioButton( hDlg, IDC_LAUNCH_NEW, IDC_DONT_LAUNCH, IDC_LAUNCH_NOT_FOUND );
SetDlgItemText( hDlg, IDC_PLAYER_NAME, g_strPlayerName );
SetDlgItemText( hDlg, IDC_SESSION_NAME, g_strSessionName );
if( FAILED( hr = EnumRegisteredApplications( hDlg ) ) )
return DXTRACE_ERR( TEXT("EnumRegisteredApplications"), hr );
if( FAILED( hr = EnumServiceProviders( hDlg ) ) )
return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
WSADATA WSAData;
_tcscpy( g_strLocalIP, TEXT("") );
if( WSAStartup (MAKEWORD(1,0), &WSAData) == 0)
{
CHAR strLocalHostName[MAX_PATH];
gethostname( strLocalHostName, MAX_PATH );
HOSTENT* pHostEnt = gethostbyname( strLocalHostName );
if( pHostEnt )
{
in_addr* pInAddr = (in_addr*) pHostEnt->h_addr_list[0];
char* strLocalIP = inet_ntoa( *pInAddr );
if( strLocalIP )
DXUtil_ConvertAnsiStringToGeneric( g_strLocalIP, strLocalIP );
}
WSACleanup();
}
SetupAddressFields( hDlg );
int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
if( pSPGuid != NULL )
{
g_pCurSPGuid = pSPGuid;
EnumAdapters( hDlg, pSPGuid );
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SetupAddressFields
// Desc: Based on the SP selected, update the address UI
//-----------------------------------------------------------------------------
VOID SetupAddressFields( HWND hDlg )
{
int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
if( nSPIndex == LB_ERR )
return;
GUID* pGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
if( pGuid == NULL )
return;
BOOL bHosting = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
if( *pGuid == CLSID_DP8SP_TCPIP )
{
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("2323") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("Port:") );
if( bHosting )
{
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
}
else
{
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, g_strLocalIP );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("IP Address:") );
}
}
else if( *pGuid == CLSID_DP8SP_MODEM )
{
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), TRUE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("Phone Number:") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
}
else
{
// pGuid is CLSID_DP8SP_IPX or CLSID_DP8SP_SERIAL or unknown
// so disable all the address lines
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE1_TEXT), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE1_TEXT, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2, TEXT("") );
EnableWindow( GetDlgItem(hDlg, IDC_ADDRESS_LINE2_TEXT), FALSE );
SetDlgItemText( hDlg, IDC_ADDRESS_LINE2_TEXT, TEXT("") );
}
}
//-----------------------------------------------------------------------------
// Name: EnumRegisteredApplications
// Desc: Enum all the lobby launchable apps and put them in the listbox
//-----------------------------------------------------------------------------
HRESULT EnumRegisteredApplications( HWND hDlg )
{
HRESULT hr;
DWORD dwSize = 0;
DWORD dwPrograms = 0;
DWORD iProgram;
BYTE* pData = NULL;
hr = g_pLobbyClient->EnumLocalPrograms( NULL, pData, &dwSize, &dwPrograms, 0 );
if( hr != DPNERR_BUFFERTOOSMALL && FAILED(hr) )
return DXTRACE_ERR( TEXT("EnumLocalPrograms"), hr );
if( dwSize == 0 )
{
MessageBox( NULL, TEXT("There are no applications registered as lobby launchable. ")
TEXT("The sample will now quit."),
g_strAppName, MB_OK | MB_ICONERROR );
EndDialog( hDlg, 0 );
return S_OK;
}
pData = new BYTE[dwSize];
if( FAILED( hr = g_pLobbyClient->EnumLocalPrograms( NULL, pData, &dwSize, &dwPrograms, 0 ) ) )
return DXTRACE_ERR( TEXT("EnumLocalPrograms"), hr );
DPL_APPLICATION_INFO* pAppInfo = (DPL_APPLICATION_INFO*) pData;
for( iProgram=0; iProgram<dwPrograms; iProgram++ )
{
TCHAR strAppName[MAX_PATH];
DXUtil_ConvertWideStringToGeneric( strAppName, pAppInfo->pwszApplicationName );
// Add the name to the listbox
int nIndex = (int) SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_ADDSTRING, 0, (LPARAM) strAppName );
// Store the guid in the listbox
GUID* pGuid = new GUID;
memcpy( pGuid, &pAppInfo->guidApplication, sizeof(GUID) );
SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_SETITEMDATA, nIndex, (LPARAM) pGuid );
pAppInfo++;
}
SAFE_DELETE_ARRAY( pData );
SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_SETCURSEL, 0, 0 );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: EnumServiceProviders()
// Desc: Fills the combobox with service providers
//-----------------------------------------------------------------------------
HRESULT EnumServiceProviders( HWND hDlg )
{
DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
HRESULT hr;
DWORD dwItems = 0;
DWORD dwSize = 0;
int nIndex;
// Enumerate all DirectPlay service providers, and store them in the listbox
hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo, &dwSize,
&dwItems, 0 );
if( hr != DPNERR_BUFFERTOOSMALL )
return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
if( FAILED( hr = g_pDP->EnumServiceProviders( NULL, NULL, pdnSPInfo,
&dwSize, &dwItems, 0 ) ) )
return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
for ( DWORD i = 0; i < dwItems; i++ )
{
TCHAR strName[MAX_PATH];
DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
// Found a service provider, so put it in the listbox
nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_ADDSTRING,
0, (LPARAM) strName );
// Store pointer to GUID in listbox
GUID* pGuid = new GUID;
memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETITEMDATA,
nIndex, (LPARAM) pGuid );
pdnSPInfoEnum++;
}
SAFE_DELETE_ARRAY( pdnSPInfo );
// Try to select the default preferred provider
nIndex = (int)SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_FINDSTRINGEXACT, (WPARAM)-1,
(LPARAM)g_strPreferredProvider );
if( nIndex != LB_ERR )
SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, nIndex, 0 );
else
SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_SETCURSEL, 0, 0 );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: EnumAdapters()
// Desc: Fills the combobox with adapters for a specified SP
//-----------------------------------------------------------------------------
HRESULT EnumAdapters( HWND hDlg, GUID* pSPGuid )
{
DPN_SERVICE_PROVIDER_INFO* pdnSPInfo = NULL;
TCHAR strName[MAX_PATH];
HRESULT hr;
DWORD dwItems = 0;
DWORD dwSize = 0;
int nIndex;
int nAllAdaptersIndex = 0;
SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_RESETCONTENT, 0, 0 );
// Enumerate all DirectPlay service providers, and store them in the listbox
hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo, &dwSize,
&dwItems, 0 );
if( hr != DPNERR_BUFFERTOOSMALL )
return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
pdnSPInfo = (DPN_SERVICE_PROVIDER_INFO*) new BYTE[dwSize];
if( FAILED( hr = g_pDP->EnumServiceProviders( pSPGuid, NULL, pdnSPInfo,
&dwSize, &dwItems, 0 ) ) )
return DXTRACE_ERR( TEXT("EnumServiceProviders"), hr );
DPN_SERVICE_PROVIDER_INFO* pdnSPInfoEnum = pdnSPInfo;
for ( DWORD i = 0; i < dwItems; i++ )
{
DXUtil_ConvertWideStringToGeneric( strName, pdnSPInfoEnum->pwszName );
// Found a service provider, so put it in the listbox
nIndex = (int)SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_ADDSTRING,
0, (LPARAM) strName );
if( _tcscmp( strName, TEXT("All Adapters") ) == 0 )
nAllAdaptersIndex = nIndex;
// Store pointer to GUID in listbox
GUID* pGuid = new GUID;
memcpy( pGuid, &pdnSPInfoEnum->guid, sizeof(GUID) );
SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETITEMDATA,
nIndex, (LPARAM) pGuid );
pdnSPInfoEnum++;
}
SAFE_DELETE_ARRAY( pdnSPInfo );
SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_SETCURSEL, nAllAdaptersIndex, 0 );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: LaunchApp
// Desc: Launch the selected app based on the UI settings
//-----------------------------------------------------------------------------
HRESULT LaunchApp( HWND hDlg )
{
HRESULT hr;
DPNHANDLE hApplication = NULL;
BOOL bLaunchNew = IsDlgButtonChecked( hDlg, IDC_LAUNCH_NEW );
BOOL bLaunchNotFound = IsDlgButtonChecked( hDlg, IDC_LAUNCH_NOT_FOUND );
int nAppIndex = (int) SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_GETCURSEL, 0, 0 );
GUID* pAppGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_APP_LIST, LB_GETITEMDATA, nAppIndex, 0 );
if( nAppIndex == LB_ERR || pAppGuid == NULL )
return E_INVALIDARG;
// Setup the DPL_CONNECT_INFO struct
DPL_CONNECT_INFO dnConnectInfo;
ZeroMemory( &dnConnectInfo, sizeof(DPL_CONNECT_INFO) );
dnConnectInfo.dwSize = sizeof(DPL_CONNECT_INFO);
dnConnectInfo.pvLobbyConnectData = NULL;
dnConnectInfo.dwLobbyConnectDataSize = 0;
dnConnectInfo.dwFlags = 0;
if( bLaunchNew )
dnConnectInfo.dwFlags |= DPLCONNECT_LAUNCHNEW;
if( bLaunchNotFound )
dnConnectInfo.dwFlags |= DPLCONNECT_LAUNCHNOTFOUND;
dnConnectInfo.guidApplication = *pAppGuid;
if( FAILED( hr = AllocAndInitConnectSettings( hDlg, pAppGuid, &dnConnectInfo.pdplConnectionSettings ) ) )
return S_FALSE;
hr = g_pLobbyClient->ConnectApplication( &dnConnectInfo, NULL, &hApplication,
INFINITE, 0 );
if( FAILED(hr) )
{
if( hr == DPNERR_NOCONNECTION && !bLaunchNew && !bLaunchNotFound )
{
MessageBox( NULL, TEXT("There was no waiting application. "),
g_strAppName, MB_OK | MB_ICONERROR );
}
else
{
return DXTRACE_ERR( TEXT("ConnectApplication"), hr );
}
}
else
{
TCHAR strBuffer[20];
wsprintf( strBuffer, TEXT("0x%x"), hApplication );
int nIndex = (int) SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_ADDSTRING,
0, (LPARAM) strBuffer );
SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_SETITEMDATA,
nIndex, (LPARAM) hApplication );
if( LB_ERR == SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_GETCURSEL, 0, 0 ) )
SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_SETCURSEL, 0, 0 );
}
FreeConnectSettings( dnConnectInfo.pdplConnectionSettings );
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: AllocAndInitConnectSettings
// Desc: Alloc and fill up a DPL_CONNECTION_SETTINGS. Call FreeConnectSettings
// later to free it.
//-----------------------------------------------------------------------------
HRESULT AllocAndInitConnectSettings( HWND hDlg, GUID* pAppGuid,
DPL_CONNECTION_SETTINGS** ppdplConnectSettings )
{
HRESULT hr;
BOOL bHosting = IsDlgButtonChecked( hDlg, IDC_HOST_SESSION );
BOOL bNoSettings = IsDlgButtonChecked( hDlg, IDC_NO_SETTINGS );
IDirectPlay8Address* pHostAddress = NULL;
IDirectPlay8Address* pDeviceAddress = NULL;
if( bNoSettings )
{
*ppdplConnectSettings = NULL;
return S_OK;
}
int nSPIndex = (int) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETCURSEL, 0, 0 );
GUID* pSPGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_SP_COMBO, CB_GETITEMDATA, nSPIndex, 0 );
if( *pSPGuid == CLSID_DP8SP_IPX && !bHosting )
{
MessageBox( hDlg, TEXT("A typical lobby client would have sent a complete IPX address, this ") \
TEXT("lobby client does not support this. "), g_strAppName, MB_OK );
return E_NOTIMPL;
}
if( !bHosting )
{
// Create a host address if connecting to a host,
// otherwise keep it as NULL
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address, (void **) &pHostAddress ) ) )
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
// Set the SP to pHostAddress
if( FAILED( hr = pHostAddress->SetSP( pSPGuid ) ) )
return DXTRACE_ERR( TEXT("SetSP"), hr );
}
// Create a device address to specify which device we are using
if( FAILED( hr = CoCreateInstance( CLSID_DirectPlay8Address, NULL, CLSCTX_INPROC_SERVER,
IID_IDirectPlay8Address, (void **) &pDeviceAddress ) ) )
return DXTRACE_ERR( TEXT("CoCreateInstance"), hr );
// Set the SP to pDeviceAddress
if( FAILED( hr = pDeviceAddress->SetSP( pSPGuid ) ) )
return DXTRACE_ERR( TEXT("SetSP"), hr );
// Add the adapter to pHostAddress
int nAdapterIndex = (int) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETCURSEL, 0, 0 );
GUID* pAdapterGuid = (GUID*) SendDlgItemMessage( hDlg, IDC_ADAPTER_COMBO, CB_GETITEMDATA,
nAdapterIndex, 0 );
if( FAILED( hr = pDeviceAddress->SetDevice( pAdapterGuid ) ) )
return DXTRACE_ERR( TEXT("SetDevice"), hr );
if( *pSPGuid == CLSID_DP8SP_TCPIP )
{
TCHAR strIP[MAX_PATH];
TCHAR strPort[MAX_PATH];
GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strIP, MAX_PATH );
GetDlgItemText( hDlg, IDC_ADDRESS_LINE2, strPort, MAX_PATH );
if( bHosting )
{
// Add the port to pDeviceAddress
DWORD dwPort = _ttoi( strPort );
if( FAILED( hr = pDeviceAddress->AddComponent( DPNA_KEY_PORT,
&dwPort, sizeof(dwPort),
DPNA_DATATYPE_DWORD ) ) )
return DXTRACE_ERR( TEXT("AddComponent"), hr );
}
else
{
// Add the IP address to pHostAddress
if( _tcslen( strIP ) > 0 )
{
WCHAR wstrIP[MAX_PATH];
DXUtil_ConvertGenericStringToWide( wstrIP, strIP );
if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_HOSTNAME,
wstrIP, (wcslen(wstrIP)+1)*sizeof(WCHAR),
DPNA_DATATYPE_STRING ) ) )
return DXTRACE_ERR( TEXT("AddComponent"), hr );
}
// Add the port to pHostAddress
DWORD dwPort = _ttoi( strPort );
if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PORT,
&dwPort, sizeof(dwPort),
DPNA_DATATYPE_DWORD ) ) )
return DXTRACE_ERR( TEXT("AddComponent"), hr );
}
}
else if( *pSPGuid == CLSID_DP8SP_MODEM )
{
TCHAR strPhone[MAX_PATH];
GetDlgItemText( hDlg, IDC_ADDRESS_LINE1, strPhone, MAX_PATH );
if( !bHosting )
{
// Add the phonenumber to pHostAddress
if( _tcslen( strPhone ) > 0 )
{
WCHAR wstrPhone[MAX_PATH];
DXUtil_ConvertGenericStringToWide( wstrPhone, strPhone );
if( FAILED( hr = pHostAddress->AddComponent( DPNA_KEY_PHONENUMBER,
wstrPhone, (wcslen(wstrPhone)+1)*sizeof(WCHAR),
DPNA_DATATYPE_STRING ) ) )
return DXTRACE_ERR( TEXT("AddComponent"), hr );
}
}
}
else if( *pSPGuid == CLSID_DP8SP_SERIAL )
{
// This simple client doesn't have UI to query for the various
// fields needed for the serial. So we just let DPlay popup a dialog
// to ask the user which settings are needed.
}
else
{
// Unknown SP, so leave as is
}
// Setup the DPL_CONNECTION_SETTINGS
DPL_CONNECTION_SETTINGS* pSettings = new DPL_CONNECTION_SETTINGS;
ZeroMemory( pSettings, sizeof(DPL_CONNECTION_SETTINGS) );
pSettings->dwSize = sizeof(DPL_CONNECTION_SETTINGS);
pSettings->dpnAppDesc.dwSize = sizeof(DPN_APPLICATION_DESC);
pSettings->dwFlags = 0;
if( bHosting )
pSettings->dwFlags |= DPLCONNECTSETTINGS_HOST;
pSettings->dpnAppDesc.guidApplication = *pAppGuid;
pSettings->dpnAppDesc.guidInstance = GUID_NULL;
pSettings->pdp8HostAddress = pHostAddress;
pSettings->ppdp8DeviceAddresses = new IDirectPlay8Address*;
pSettings->ppdp8DeviceAddresses[0] = pDeviceAddress;
pSettings->cNumDeviceAddresses = 1;
// Set the pSettings->dpnAppDesc.pwszSessionName
TCHAR strSessionName[MAX_PATH];
GetDlgItemText( hDlg, IDC_SESSION_NAME, strSessionName, MAX_PATH );
if( _tcslen( strSessionName ) == 0 )
{
pSettings->dpnAppDesc.pwszSessionName = NULL;
}
else
{
WCHAR wstrSessionName[MAX_PATH];
DXUtil_ConvertGenericStringToWide( wstrSessionName, strSessionName );
pSettings->dpnAppDesc.pwszSessionName = new WCHAR[wcslen(wstrSessionName)+1];
wcscpy( pSettings->dpnAppDesc.pwszSessionName, wstrSessionName );
}
// Set the pSettings->pwszPlayerName
TCHAR strPlayerName[MAX_PATH];
GetDlgItemText( hDlg, IDC_PLAYER_NAME, strPlayerName, MAX_PATH );
if( _tcslen( strPlayerName ) == 0 )
{
pSettings->pwszPlayerName = NULL;
}
else
{
WCHAR wstrPlayerName[MAX_PATH];
DXUtil_ConvertGenericStringToWide( wstrPlayerName, strPlayerName );
pSettings->pwszPlayerName = new WCHAR[wcslen(wstrPlayerName)+1];
wcscpy( pSettings->pwszPlayerName, wstrPlayerName );
}
*ppdplConnectSettings = pSettings;
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: FreeConnectSettings
// Desc: Releases everything involved in a DPL_CONNECTION_SETTINGS struct
//-----------------------------------------------------------------------------
VOID FreeConnectSettings( DPL_CONNECTION_SETTINGS* pSettings )
{
if( !pSettings )
return;
SAFE_DELETE_ARRAY( pSettings->pwszPlayerName );
SAFE_DELETE_ARRAY( pSettings->dpnAppDesc.pwszSessionName );
SAFE_DELETE_ARRAY( pSettings->dpnAppDesc.pwszPassword );
SAFE_DELETE_ARRAY( pSettings->dpnAppDesc.pvReservedData );
SAFE_DELETE_ARRAY( pSettings->dpnAppDesc.pvApplicationReservedData );
SAFE_RELEASE( pSettings->pdp8HostAddress );
SAFE_RELEASE( pSettings->ppdp8DeviceAddresses[0] );
SAFE_DELETE_ARRAY( pSettings->ppdp8DeviceAddresses );
SAFE_DELETE( pSettings );
}
//-----------------------------------------------------------------------------
// Name: DirectPlayMessageHandler
// Desc: Handler for DirectPlay messages. This function is called by
// the DirectPlay message handler pool of threads, so be care of thread
// synchronization problems with shared memory
//-----------------------------------------------------------------------------
HRESULT WINAPI DirectPlayMessageHandler( PVOID pvUserContext,
DWORD dwMessageId,
PVOID pMsgBuffer )
{
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DirectPlayLobbyMessageHandler
// Desc: Handler for DirectPlay lobby messages. This function is called by
// the DirectPlay lobby message handler pool of threads, so be careful of
// thread synchronization problems with shared memory
//-----------------------------------------------------------------------------
HRESULT WINAPI DirectPlayLobbyMessageHandler( PVOID pvUserContext,
DWORD dwMessageId,
PVOID pMsgBuffer )
{
switch( dwMessageId )
{
case DPL_MSGID_DISCONNECT:
{
PDPL_MESSAGE_DISCONNECT pDisconnectMsg;
pDisconnectMsg = (PDPL_MESSAGE_DISCONNECT)pMsgBuffer;
// We should free any data associated with the
// app here, but there is none.
// Tell the update the UI so show that a application was disconnected
// Note: The lobby handler must not become blocked on the dialog thread,
// since the dialog thread will be blocked on lobby handler thread
// when it calls ConnectApplication(). So to avoid blocking on
// the dialog thread, we'll post a message to the dialog thread.
PostMessage( g_hDlg, WM_APP_APPDISCONNECTED, 0, pDisconnectMsg->hDisconnectId );
break;
}
case DPL_MSGID_RECEIVE:
{
PDPL_MESSAGE_RECEIVE pReceiveMsg;
pReceiveMsg = (PDPL_MESSAGE_RECEIVE)pMsgBuffer;
// The lobby app sent us data. This sample doesn't
// expected data from the app, but it is useful
// for more complex lclients.
break;
}
case DPL_MSGID_SESSION_STATUS:
{
PDPL_MESSAGE_SESSION_STATUS pStatusMsg;
pStatusMsg = (PDPL_MESSAGE_SESSION_STATUS)pMsgBuffer;
TCHAR* strBuffer = new TCHAR[200];
wsprintf( strBuffer, TEXT("0x%x: "), pStatusMsg->hSender );
switch( pStatusMsg->dwStatus )
{
case DPLSESSION_CONNECTED:
_tcscat( strBuffer, TEXT("Session connected") ); break;
case DPLSESSION_COULDNOTCONNECT:
_tcscat( strBuffer, TEXT("Session could not connect") ); break;
case DPLSESSION_DISCONNECTED:
_tcscat( strBuffer, TEXT("Session disconnected") ); break;
case DPLSESSION_TERMINATED:
_tcscat( strBuffer, TEXT("Session terminated") ); break;
case DPLSESSION_HOSTMIGRATED:
_tcscat( strBuffer, TEXT("Host migrated") ); break;
case DPLSESSION_HOSTMIGRATEDHERE:
_tcscat( strBuffer, TEXT("Host migrated to this client") ); break;
default:
{
TCHAR strStatus[30];
wsprintf( strStatus, TEXT("%d"), pStatusMsg->dwStatus );
_tcscat( strBuffer, strStatus );
break;
}
}
// Tell the update the UI so show that a application status changed
// Note: The lobby handler must not become blocked on the dialog thread,
// since the dialog thread will be blocked on lobby handler thread
// when it calls ConnectApplication(). So to avoid blocking on
// the dialog thread, we'll post a message to the dialog thread.
PostMessage( g_hDlg, WM_APP_SETSTATUS, 0, (LPARAM) strBuffer );
break;
}
case DPL_MSGID_CONNECTION_SETTINGS:
{
PDPL_MESSAGE_CONNECTION_SETTINGS pConnectionStatusMsg;
pConnectionStatusMsg = (PDPL_MESSAGE_CONNECTION_SETTINGS)pMsgBuffer;
// The app has changed the connection settings.
// This simple client doesn't handle this, but more complex clients may
// want to.
break;
}
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: SendMsgToApp
// Desc: Send a dummy message to a connected app for demo purposes
//-----------------------------------------------------------------------------
HRESULT SendMsgToApp( HWND hDlg )
{
TCHAR strBuffer[MAX_PATH];
HRESULT hr;
int nConnectIndex = (int) SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_GETCURSEL, 0, 0 );
if( nConnectIndex == LB_ERR )
return S_OK;
DPNHANDLE hApplication = (DPNHANDLE) SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS,
LB_GETITEMDATA, nConnectIndex, 0 );
// For demonstration purposes, just send a buffer to the app. This can be used
// by more complex lobby clients to pass custom information to apps that which
// can then recieve and process it.
BYTE buffer[20];
memset( buffer, 0x03, 20 );
if( FAILED( hr = g_pLobbyClient->Send( hApplication, buffer, 20, 0 ) ) )
{
DXTRACE_ERR( TEXT("Send"), hr );
wsprintf( strBuffer, TEXT("Failure trying to send message to 0x%0.8x."), hApplication );
MessageBox( NULL, strBuffer, g_strAppName, MB_OK | MB_ICONERROR );
}
else
{
wsprintf( strBuffer, TEXT("Successfully sent a message to 0x%0.8x."), hApplication );
MessageBox( NULL, strBuffer, g_strAppName, MB_OK | MB_ICONERROR );
}
return S_OK;
}
//-----------------------------------------------------------------------------
// Name: DisconnectFromApp
// Desc: Disconnect from an app
//-----------------------------------------------------------------------------
HRESULT DisconnectFromApp( HWND hDlg )
{
HRESULT hr;
int nConnectIndex = (int) SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_GETCURSEL, 0, 0 );
if( nConnectIndex == LB_ERR )
return S_OK;
DPNHANDLE hApplication = (DPNHANDLE) SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS,
LB_GETITEMDATA, nConnectIndex, 0 );
if( FAILED( hr = g_pLobbyClient->ReleaseApplication( hApplication, 0 ) ) )
{
DXTRACE_ERR( TEXT("LaunchApp"), hr );
MessageBox( NULL, TEXT("Failure trying to disconnect from app. "),
g_strAppName, MB_OK | MB_ICONERROR );
}
SendDlgItemMessage( hDlg, IDC_ACTIVE_CONNECTIONS, LB_DELETESTRING, nConnectIndex, 0 );
return S_OK;
}